<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>贪吃蛇🐍</title>
    <link href="https://cdn.bootcss.com/limonte-sweetalert2/8.11.8/sweetalert2.min.css" rel="stylesheet" />
</head>

<body>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <script src="https://cdn.bootcss.com/limonte-sweetalert2/8.11.8/sweetalert2.min.js"></script>
    <canvas id="canvas" width="400" height="400"></canvas>
    <br />
    <button id="restart">重新开始</button>
    <button id="suspend">暂停游戏</button>
    <button id="go-on">继续游戏</button>
    <br />
    <p>请点击重新开始按钮；按 ↑ ↓ ← → 控制方向</p>
    <p>达到16分即可获得胜利！加油吧！</p>
    <script>
        let canvas = document.getElementById("canvas");
        let ctx = canvas.getContext("2d");
        let width = canvas.width;
        let height = canvas.height;
        let animationTime = 100;
        let blockSize = 10;
        let widthInBlocks = width / blockSize;
        let heightInBlocks = height / blockSize;

        let score = 0;

        //? 绘制边框
        function drawBorder() {
            ctx.fillStyle = "Gray";
            ctx.fillRect(0, 0, width, blockSize);
            ctx.fillRect(0, height - blockSize, width, blockSize);
            ctx.fillRect(0, 0, blockSize, height);
            ctx.fillRect(width - blockSize, 0, blockSize, height);
        }

        //? 显示分数
        function drawScore() {
            ctx.textBaseline = "top";
            ctx.textAlign = "left";
            ctx.font = "22px 华文新魏";
            ctx.fillStyle = "Black";
            ctx.fillText("分数：" + score, blockSize, blockSize);
        }

        //? 结束游戏
        function gameOver() {
            playing = false;
            ctx.font = "35px 楷体";
            ctx.fillStyle = "Black";
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            Swal.fire("哎呦……", "你挂了！😥", "error");
            ctx.fillText("再来一次吧！😄", width / 2, height / 2);
        }

        function Victory() {
            playing = false;
            ctx.font = "35px 楷体";
            ctx.fillStyle = "Black";
            ctx.textAlign = "center";
            ctx.textBaseline = "middle";
            Swal.fire("干的漂亮！😀", "游戏胜利", "success");
            ctx.fillText("再来一次吧！😎", width / 2, height / 2);
        }

        function circle(x, y, radius, fillCircle) {
            ctx.beginPath();
            ctx.arc(x, y, radius, 0, Math.PI * 2, false);
            if (fillCircle) {
                ctx.fill();
            } else {
                ctx.stroke();
            }
        }
        //? 来一个 Block 构造函数；
        class Block {
            constructor(col, row) {
                this.col = col;
                this.row = row;
            }
            drawSquare(color) {
                let x = this.col * blockSize;
                let y = this.row * blockSize;
                ctx.fillStyle = color;
                ctx.fillRect(x, y, blockSize, blockSize);
            }
            drawCircle(color) {
                let centerX = this.col * blockSize + blockSize / 2;
                let centerY = this.row * blockSize + blockSize / 2;
                ctx.fillStyle = color;
                circle(centerX, centerY, blockSize / 2, true);
            }
            //# 判断苹果和贪吃蛇的头部是否处于同一位置，即判断贪吃蛇是否吃掉了苹果
            equal(otherBlock) {
                return this.col === otherBlock.col && this.row === otherBlock.row;
            }
        }

        //? Snake构造函数
        class Snake {
            constructor() {
                this.segments = [new Block(7, 5), new Block(6, 5), new Block(5, 5)];
                this.direction = "right"; //当前位置
                this.nextDirection = "right"; //下一个动画步骤将要运动的方向
            }
            //? 绘制贪吃蛇
            draw() {
                this.segments[0].drawSquare("#4dff4d");
                for (let i = 1; i < this.segments.length; i += 2) {
                    this.segments[i].drawSquare("#ffff4d");
                }
                for (let i = 2; i < this.segments.length; i += 2) {
                    this.segments[i].drawSquare("#809fff");
                }
            }
            // 添加Move方法
            move() {
                let head = this.segments[0];
                let newHead;
                this.direction = this.nextDirection;
                if (this.direction === "right") {
                    newHead = new Block(head.col + 1, head.row);
                } else if (this.direction === "down") {
                    newHead = new Block(head.col, head.row + 1);
                } else if (this.direction === "left") {
                    newHead = new Block(head.col - 1, head.row);
                } else if (this.direction === "up") {
                    newHead = new Block(head.col, head.row - 1);
                }
                if (this.checkCollision(newHead)) {
                    gameOver();
                    return;
                }
                if (score >= 16) {
                    Victory();
                    return;
                }
                this.segments.unshift(newHead); //# 添加贪吃蛇新的头部
                if (newHead.equal(apple.position)) {
                    score++;
                    animationTime -= 5;
                    apple.move();
                } else {
                    this.segments.pop(); //# 删掉贪吃蛇的尾巴
                }
            }
            checkCollision(head) {
                let leftCollision = head.col === 0; //🐍跟左墙碰撞
                let topCollision = head.row === 0;
                let rightCollision = head.col === widthInBlocks - 1;
                let bottomCollision = head.row === heightInBlocks - 1;
                let wallCollision =
                    leftCollision || topCollision || rightCollision || bottomCollision;
                let selfCollision = false;
                for (let i = 0; i < this.segments.length; i++) {
                    if (head.equal(this.segments[i])) {
                        selfCollision = true;
                    }
                }
                return wallCollision || selfCollision;
            }
            //? 检查玩家是否进行非法掉头，防止玩家进行四种非法调头
            setDirection(newDirection) {
                if (this.direction === "up" && newDirection === "down") {
                    return;
                } else if (this.direction === "right" && newDirection === "left") {
                    return;
                } else if (this.direction === "down" && newDirection === "up") {
                    return;
                } else if (this.direction === "left" && newDirection === "right") {
                    return;
                }
                this.nextDirection = newDirection;
            }
        }

        //? 用键盘设置贪吃蛇方向
        let directions = {
            37: "left",
            38: "up",
            39: "right",
            40: "down"
        };

        $("body").keydown(function (event) {
            let newDirection = directions[event.keyCode];
            console.log(newDirection);
            if (newDirection !== undefined) {
                snake.setDirection(newDirection);
            }
        });

        $("#suspend").click(function () {
            playing = false;
        });
        $("#go-on").click(function () {
            playing = true;
            gameLoop();
        });
        $("#restart").click(function () {
            // location.reload()
            animationTime = 100;
            snake = new Snake();
            apple = new Apple();
            score = 0;
            playing = true;
            clearTimeout(myTimer);
            gameLoop();
        });

        //? 创建苹果
        class Apple {
            constructor() {
                this.position = new Block(10, 10);
            }
            draw() {
                this.position.drawCircle("#ff0000");
            }
            move() {
                let randomCol = Math.floor(Math.random() * (widthInBlocks - 4)) + 2;
                let randomRow = Math.floor(Math.random() * (widthInBlocks - 4)) + 2;
                this.position = new Block(randomCol, randomRow);
            }
        }

        //! 游戏启动代码
        let snake = new Snake();
        let apple = new Apple();
        let playing = true;

        //? 游戏流程（游戏的核心逻辑？）
        let gameLoop = function () {
            ctx.clearRect(0, 0, width, height);
            drawScore();
            snake.move();
            snake.draw();
            apple.draw();
            drawBorder();
            if (playing) {
                myTimer = setTimeout(gameLoop, animationTime);
            }
        };

        gameLoop();

    </script>
</body>

</html>
